package hh.engine;

import hh.util.Asserts;

public class Parser {
    boolean debug;
    Reader reader;
    
    public Parser(Reader reader) {
        this.reader = reader;
    }
    
    public static Nodes parse(Reader reader) {
        Parser parser = new Parser(reader);
        return parser.execute();
    }
    
    private Nodes execute() {
        Nodes root = new Nodes(reader);
        int start = 0;
        while (reader.hasNextString("<%")) {
            parseText(start, reader.position - 2, root);
            start = reader.position;
            char c = reader.forward();
            switch (c) {
                case '@':
                    parseImport(start, root);
                    break;
                case '=':
                    parseExpr(start, root);
                    break;
                default:
                    parseScript(start, root);
                    break;
            }
            start = reader.position;
        }
        if (reader.hasText())
            parseEnd(start, root);
        return root;
    }
    
    private void parseEnd(int start, Nodes root) {
        root.new Text(start, reader.data.length);
    }
    
    // <%=
    private void parseExpr(int start, Nodes root) {
        reader.skipSpaces();
        Asserts.False(reader.hasNextString("%>"), "没有结尾%>\n" + newString(start));
        root.new Expr(start - 2, reader.position);
    }
    
    private void parseImport(int start, Nodes root) {
        reader.skipSpaces();
        Asserts.True(!reader.match("page"), "<%@目前仅支持page指令");
        reader.skipSpaces();
        Asserts.True(!reader.match("import"), "<%@page 目前仅支持import指令");
        
        
        reader.skipSpaces(); // import =
        Asserts.True(reader.peek() != '=', "<%@page import 必须加=号");
        reader.forward();
        reader.skipSpaces(); // import = "
        
        Asserts.True(reader.peek() != '"', "<%@page import= 必须加\"号");
        reader.forward();
        int s = reader.position;
        
        
        Asserts.True(!reader.nextChar('"'), "<%@page import=\"xxx 必须加以\"号结尾");
        int end = reader.position;
        reader.skipSpaces();
        Asserts.True(!reader.match("%>"), "没有结尾%>");
        
        Nodes.Import node = root.new Import(start - 2, reader.position);
        node.setBody(new String(reader.data, s, end - s - 1));
    }
    
    
    private void parseText(int start, int end, Nodes root) {
        if (reader.peek(-4) == '\r') {
            end = end - 2;
        } else if (reader.peek(-3) == '\n') {
            end = end - 1;
        }
        root.new Text(start, end);
    }
    
    private void parseScript(int start, Nodes root) {
        reader.skipSpaces();
        int s = reader.position;
        Asserts.True(!reader.hasNextString("%>"), "没有结束符号'%>'");
        root.new Script(start - 2, reader.position);
    }
    
    private String newString(int start) {
        return new String(reader.data, start, reader.position - start);
    }
    
    
}
